extends Control

@export_category('task entity')
@export var taskEn:TaskEntity

@onready var subtaskScene = preload("res://pages/task/subtask.tscn")

#获得所有组件
@onready var taskNameLE = %taskNameLE
@onready var taskDesTE = %taskDesTE
@onready var selectAbilityBtn = %selectAbiltyBtn

@onready var startTimeLE = %startTimeLE
@onready var endTimeLE = %endTimeLE
@onready var deadLineLE = %DeadLineLE

@onready var workingHoursSpinbox = $PanelContainer/VBoxContainer/ScrollContainer/VBoxContainer/PanelContainer/VBoxContainer/GridContainer3/HBoxContainer/PanelContainer/SpinBox
@onready var mileStoneNumberOB = %milestomeNumerOptionButton
@onready var singleEpochOB = %singleEpochOB
@onready var epochNumberSpinbox = $PanelContainer/VBoxContainer/ScrollContainer/VBoxContainer/PanelContainer/VBoxContainer/GridContainer2/PanelContainer/SpinBox
@onready var workingDayComp = %workingDaysComp
@onready var workingPeriodsComp = %workingPeroidsComp
@onready var subtask_container = %subtaskVBContainer

@onready var ability_popup_panel = %PopupPanel
@onready var datePicker: PanelContainer = %datePicker
@onready var curretnLE = startTimeLE
@onready var imgFileDialog = %imgDialog

@onready var scroll_style = preload('res://assets/theme/taskList_scroll.tres')

var is_new_task = false

# Called when the node enters the scene tree for the first time.
func _ready():
	# 初始化两个下拉按钮
	init_milestone_and_epoch_length_ob()
	ability_popup_panel.ability_selected.connect(_on_ability_selected)
	%msg_timer.timeout.connect(_hide_msg)
	Signalbus.date_selected.connect(_on_date_selected)
	Signalbus.subtask_deled.connect(_on_subtask_deled)
	
	#imgFileDialog.filters = ["Image files (*.png, *.jpg, *.jpeg, *.svg)", "*.png ; *.jpg ; *.jpeg; *.svg"]
	#imgFileDialog.add_filter('*.png','Image File')
	#imgFileDialog.add_filter('*.jpg','Image File')
	#imgFileDialog.add_filter('*.hpeg','Image File')
	#imgFileDialog.add_filter('*.svg','Image File')
	if GlobalVariables.settingData.useWideScrollbar:
		%ScrollContainer.get_v_scroll_bar().custom_minimum_size.x = 25
		scroll_style.content_margin_right = 30
	else:
		%ScrollContainer.get_v_scroll_bar().custom_minimum_size.x = 5
		scroll_style.content_margin_right = 10
	
	%ScrollContainer.add_theme_stylebox_override('panel',scroll_style)
	#debug_demo()
	if taskEn != null:
		_set_taskEn(taskEn)

func _input(event: InputEvent) -> void:
	if event is InputEventMouseButton:
		if event.button_index == MOUSE_BUTTON_LEFT and event.pressed :
			if datePicker.visible and !datePicker.get_global_rect().has_point(event.global_position):
				datePicker.hide()
			
			if ability_popup_panel.visible and !ability_popup_panel.get_global_rect().has_point(event.global_position):
				ability_popup_panel.hide()

func init_milestone_and_epoch_length_ob():
	mileStoneNumberOB.clear()
	singleEpochOB.clear()
	for num in GlobalVariables.milesyone_numbers:
		mileStoneNumberOB.add_item(str(num))
	
	for length in GlobalVariables.epoch_lengths:
		singleEpochOB.add_item(str(length))

func debug_demo():
	#taskEn = GlobalVariables.load_test_task_demo()
	if taskEn != null:
		_set_taskEn(taskEn)
	
#进行设置绑定
func _set_taskEn(_taskEn:TaskEntity):
	taskNameLE.set_meta('task_id',_taskEn.tid)
	taskNameLE.text = _taskEn.name
	taskDesTE.text = _taskEn.description
	_set_ability_data(GlobalVariables.get_ability(taskEn.related_ability))
	_set_task_img(_taskEn.img_path)
	startTimeLE.text = _taskEn.start_time
	endTimeLE.text = _taskEn.end_time
	deadLineLE.text = _taskEn.deadline
	workingHoursSpinbox.value = _taskEn.working_hours
	mileStoneNumberOB.selected = _taskEn.milestone_number
	singleEpochOB.selected = _taskEn.single_epoch_length
	epochNumberSpinbox.value = _taskEn.epoch_num
	workingDayComp._set_days(_taskEn.working_days)
	workingPeriodsComp._set_periods(_taskEn.prefered_periods)
	add_all_subtask_view(_taskEn)

func clear_subtasks():
	for child in subtask_container.get_children():
		subtask_container.remove_child(child)
		child.queue_free()

func add_all_subtask_view(_taskEn:TaskEntity):
	clear_subtasks()
	var subtask_index = 1
	for subtask in _taskEn.subtasks:
		subtask.subtask_seq_no = subtask_index
		_add_subtask(subtask)
		subtask_index +=1

func _new_taskEn():
	if taskEn == null:
		taskEn = TaskEntity.new()
		taskEn.tid = 'T_'+GlobalVariables.uuid_util.v4()
		is_new_task = true
		
#从表单中获得taskEntity需要的内容
func _refresh_taskEn():
	_new_taskEn()
	taskEn.name = taskNameLE.text
	taskEn.description = taskDesTE.text
	taskEn.related_ability = selectAbilityBtn.get_meta('ability_data',null)
	taskEn.start_time = startTimeLE.text
	taskEn.end_time = endTimeLE.text
	taskEn.deadline = deadLineLE.text
	taskEn.working_hours = workingHoursSpinbox.value
	taskEn.milestone_number = mileStoneNumberOB.selected
	taskEn.single_epoch_length = singleEpochOB.selected
	taskEn.epoch_num = epochNumberSpinbox.value
	taskEn.working_days = workingDayComp._get_selected_days()
	taskEn.prefered_periods = workingPeriodsComp._get_working_periods()
	taskEn.subtasks.clear()
	taskEn.subtasks = get_subtasks()


## 获得子任务数据
func get_subtasks():
	var subtasks:Array[SubtaskEntity] = []
	if subtask_container.get_child_count()>0:
		for subtask in subtask_container.get_children():
			var subtaskEn:SubtaskEntity = subtask._get_subtask_entity()
			subtaskEn.related_schedules = subtask.get_meta('schedules',[])
			subtasks.append(subtaskEn)
	return subtasks

func _add_subtask(subtaskEn:SubtaskEntity):
	var subtask = subtaskScene.instantiate()
	subtask.subtaskEn = subtaskEn
	subtask.set_meta('schedules',subtaskEn.related_schedules)
	subtask_container.add_child(subtask)

#保存当前任务
func _on_save_task_pressed():
	if save_taskEn():
		_show_msg('任务保存成功')
		Signalbus.task_added.emit(taskEn)

func save_taskEn():
	_refresh_taskEn()
	if validate_taskEntity():
		GlobalVariables.save_task(taskEn)
		return true
	
	return false

func validate_taskEntity()->bool:
	if validate_startDate() and validate_Deadline() and validate_endTime() and validate_subtask_length() and \
		validate_working_days() and validate_working_period():
		return true
	return false

func validate_working_days()->bool:
	if taskEn.working_days.size()==0:
		_show_msg('至少选择一天工作时间')
		return false
	return true

func validate_working_period()->bool:
	if taskEn.prefered_periods.size()==0:
		_show_msg('至少选择一个偏好工作时间段')
		return false
	return true

func validate_subtask_length()->bool:
	# 子任务的长度是否和预估长度一致
	var subtask_length = 0
	for subtask in taskEn.subtasks:
		subtask_length+=subtask.subtask_hours
	
	if subtask_length != taskEn.working_hours:
		
		_show_msg('子任务长度与预估长度不一致')
		if GlobalVariables.settingData.autoUpdateWorkingHoursBySubtasks:
			taskEn.working_hours = subtask_length
			_set_taskEn(taskEn)
			
		return false
		
	return true

func validate_Deadline()->bool:
	# Deadline不早于今天
	var deadlineDate = time_str_2_date(taskEn.deadline) 
	if deadlineDate.is_before(GlobalVariables.get_current_date()):
		_show_msg('Deadline要不早于今天')
		return false
	
	if deadlineDate.is_before(time_str_2_date(taskEn.start_time)):
		_show_msg('Deadline应该不早于开始时间')
		return false
	return true

func validate_endTime()->bool:
	# Deadline不早于今天
	var endTimeDate = time_str_2_date(taskEn.end_time) 
	if endTimeDate.is_before(GlobalVariables.get_current_date()):
		_show_msg('结束时间要不早于今天')
		return false
	
	if endTimeDate.is_before(time_str_2_date(taskEn.start_time)):
		_show_msg('结束时间应该不早于开始时间')
		return false
		
	if endTimeDate.is_after(time_str_2_date(taskEn.deadline)):
		_show_msg('结束时间应该不晚于dealline')
		return false
	
	return true

func validate_startDate()->bool:
	# 开始时间要晚于当前时间
	var startDate = time_str_2_date(taskEn.start_time) 
	if is_new_task and startDate.is_before(GlobalVariables.get_current_date()):
		_show_msg('开始时间要不早于今天')
		return false
	return true

func time_str_2_date(timeStr:String)->Calendar.Date:
	var splits = timeStr.split('/')
	return Calendar.Date.new(int(splits[0]),int(splits[1]),int(splits[2]))
	
#当选择技能点击时
func _on_select_abilty_btn_pressed():
	ability_popup_panel.show_poppanel()

# pass 
func _on_ability_selected(ability_data:AbilityEntity):
	_set_ability_data(ability_data)
	
func _set_ability_data(ability_data:AbilityEntity):
	if ability_data == null:
		selectAbilityBtn.set_meta('ability_data',ability_data.id)
		return
	selectAbilityBtn.text = ability_data.name
	selectAbilityBtn.add_theme_color_override("font_color",ability_data.color)
	selectAbilityBtn.add_theme_color_override("font_focus_color",ability_data.color)
	
	selectAbilityBtn.set_meta('ability_data',ability_data.id)


func _show_msg(msg:String):
	%msg_label.text  = msg
	%msg_label.add_theme_color_override("font_color",Color.CRIMSON)
	%msg_timer.start()

func _hide_msg():
	%msg_label.add_theme_color_override("font_color",Color.html('#f2f5f9'))


func _on_start_time_le_focus_entered():
	curretnLE = startTimeLE
	datePicker.show()

func _on_date_selected(date:Calendar.Date):
	curretnLE.text =  '%d/%02d/%02d' % [date.year,date.month,date.day]
	datePicker.hide()
	_refresh_taskEn()

#func _on_start_time_le_focus_exited():
	#datePicker.hide()

func _on_end_time_le_focus_entered():
	curretnLE = endTimeLE
	datePicker.show()

#func _on_end_time_le_focus_exited():
	#datePicker.hide()

func _on_dead_line_le_focus_entered():
	curretnLE = deadLineLE
	datePicker.show()

#func _on_dead_line_le_focus_exited():
	#datePicker.hide()

func _on_spin_box_value_changed(value):
	#_refresh_taskEn()
	# 计算当前值除以dealine距离开始时间的长度
	if validate_startDate() and validate_Deadline() and validate_endTime() and validate_subtask_length():
		%date_label.show()
		%date_label.text = '(已完成%.1f小时，工作剩余%d天，平均每天工作%.2f小时！)' % [taskEn.hours_used, cal_task_end_length(),float(value-taskEn.hours_used)/cal_task_end_length()]
		%date_label.set_meta('hours_per_day',float(value-taskEn.hours_used)/cal_task_end_length())
		
		_on_single_epoch_ob_item_selected(taskEn.single_epoch_length)

func cal_task_end_length()->int:
	var startDate = time_str_2_date(taskEn.start_time)
	var endDate = time_str_2_date(taskEn.end_time)
	
	if taskEn.working_days == null or taskEn.working_days.size()==0:
		return endDate.days_to(startDate)+1
	
	var today = GlobalVariables.get_current_date()
	if startDate.is_before(today):
		startDate = today
	
	#计算需要能够工作多少天
	var day_num = 0
	while not startDate.is_after(endDate):
	# 需要根据 working days重新计算可以工作多少天
		if startDate.duplicate().get_weekday_iso() in taskEn.working_days:
			day_num += 1
		startDate.add_days(1)
	return day_num

func cal_task_dead_length()->int:
	return abs(time_str_2_date(taskEn.start_time).days_to(time_str_2_date(taskEn.deadline)))

func _on_single_epoch_ob_item_selected(index):
	var single_epoch_hour = GlobalVariables.epoch_lengths[index]/float(60)
	var epoch_numbers = int(ceil(%date_label.get_meta('hours_per_day')/single_epoch_hour))
	%hours_label.text = '(当前计划需要每天工作%d小节)' % epoch_numbers
	epochNumberSpinbox.value = epoch_numbers
	%hours_label.show()

func _on_add_subtask_btn_pressed():
	_refresh_taskEn()
	#首先获得当前subtasks的数量
	var subtask_num = taskEn.subtasks.size()
	var subtaskEn = SubtaskEntity.new()
	subtaskEn.subtask_seq_no = subtask_num+1
	subtaskEn.belonged_task_id = taskEn.tid
	_add_subtask(subtaskEn)
	scrollToEnd()

func _on_subtask_deled(_taskID:String, subtaskEn:SubtaskEntity):
	#将subtaskEn从原来的taskEn的subtasks里面去掉
	taskEn.subtasks.erase(subtaskEn)
	# 将子任务关联的schedule删除掉
	add_all_subtask_view(taskEn)
	GlobalVariables.del_subtask_schedules(subtaskEn)

func scrollToEnd():
	var scrollbar = %ScrollContainer.get_v_scroll_bar()
	scrollbar.changed.connect(_scroll_to_bottom)

func _scroll_to_bottom():
	var scrollbar = %ScrollContainer.get_v_scroll_bar()
	scrollbar.value = scrollbar.max_value
	
func _on_select_img_button_pressed():
	imgFileDialog.show()

func _on_img_dialog_file_selected(path:String):
	if not path.get_extension() in ['png','svg','jpg','jpeg']:
		_show_msg('图片只支持四种格式(png, svg, jpg, jpeg)')
		return 
	# 将选择的文件copy到user文件夹，返回新路径
	var img_path = GlobalUtil.copy_img_to_user_dir(path)
	#更新img的list
	GlobalVariables.update_img_file(img_path.get_file())
	# copy之后将copy img的时间 存入到version file里面
	GlobalVariables.update_file_version_time(img_path.get_file())
	_set_task_img(img_path)
	if taskEn == null:
		_new_taskEn()
		
	taskEn.img_path = img_path

func _set_task_img(img_path:String):
	var texture =  GlobalUtil.create_texture_from_absolute_path(img_path)
	%select_img_button.texture_normal = texture
	%select_img_button.texture_pressed = texture
	%select_img_button.texture_hover = texture
	%select_img_button.texture_focused = texture

# 自动规划日程
func _on_gen_schedule_tn_pressed():
	
	if not save_taskEn():
		return
	_show_msg('自动保存任务，开始日程规划')
	_refresh_taskEn()
	
	var epoch_num = recal_epoch_num()
	var epoch_length = GlobalVariables.epoch_lengths[taskEn.single_epoch_length]
	
	if not check_working_time_space(epoch_num, epoch_length):
		_show_msg('偏好时间区间不够，请重新规划')
		return 
	
	var subtask_results = GlobalUtil.arrange_task_schedules(taskEn)
	
	if subtask_results == null:
		_show_msg('偏好时间区间不够，请重新规划')
	else:
		for task_no in range(subtask_results.size()):
			# 保存schedule和taskEntity
			subtask_container.get_child(task_no).set_meta('schedules',subtask_results[task_no])
	
	if save_taskEn():
		_show_msg('生成日程并保存完成')

# 检查任务进度
func check_task_process()->bool:
	
	var in_planed = true
	# 首先去获得今天之前的子任务
	var task_hours_used = 0
	for subtask in taskEn.subtasks:
		# 获得subtask关联的schedules
		var schedule_ids = subtask.related_schedules
		var subtask_hours_used  = 0
		for schedule_id in schedule_ids:
			var scheduleData = GlobalVariables.get_schedule_data(schedule_id)
			var state = GlobalVariables.check_schedule_state(scheduleData)
			#if state == GlobalVariables.ScheduleState.UNFINISHED or state == GlobalVariables.ScheduleState.DELAYED:
				##这两种表示没有完成
				#pass
			#
			if state == GlobalVariables.ScheduleState.FINISHED:
				# 表示已经完成
				subtask_hours_used += ceili(taskEn.single_epoch_length/float(60))
		
		subtask.subtask_hours_used = subtask_hours_used
		task_hours_used += subtask_hours_used
		if subtask.subtask_hours > subtask.subtask_hours_used:
			in_planed = false
	
	taskEn.hours_used = task_hours_used
	return in_planed

# 重新计算epoch_num
func recal_epoch_num()->int:
	var hours_last = taskEn.working_hours - taskEn.hours_used
	var days_last = cal_task_end_length()
	return ceili(hours_last/days_last)

## todo 这里需要调用时间进行重新计算
#检查选择的工作偏好时间是否满足需求
func check_working_time_space(epoch_num:int,epoch_length:int)->bool:
	var time_zone_length = 0
	for zone in taskEn.prefered_periods:
		time_zone_length += GlobalVariables.period_time_zone_length[zone]
	if epoch_num*epoch_length < time_zone_length:
		return true
	return false
		
		
func _widy_scrollbar(v_scroll_bar:VScrollBar):
	v_scroll_bar.custom_minimum_size.x = 50
	
